﻿using Sidvall.Serialization;
using System.Collections.Generic;
using System.Linq;
using System.Security.Principal;


namespace Sidvall.Security.Uwp
{
    public class ClaimsPrincipalManager : IClaimsPrincipalManager
    {
        #region Public Members

        #region AddClaim

        public void AddClaim(IIdentity identity, Claim claim)
        {
            System.Security.Claims.ClaimsIdentity claimsIdentity;
            System.Security.Claims.Claim item;
            IClaimProvider claimProvider;

            if (identity == null)
                return;
            if (claim == null)
                return;
            claimsIdentity = identity as System.Security.Claims.ClaimsIdentity;
            if (claimsIdentity != null)
            {
                item = Convert(claim);
                claimsIdentity.AddClaim(item);
            }
            else
            {
                claimProvider = identity as IClaimProvider;
                if (claimProvider != null)
                    claimProvider.AddClaim(claim);
            }
        }

        #endregion
        #region AddClaims

        public void AddClaims(IIdentity identity, IEnumerable<Claim> claims)
        {
            System.Security.Claims.ClaimsIdentity claimsIdentity;
            System.Security.Claims.Claim item;
            IClaimProvider claimProvider;

            if (identity == null)
                return;
            if (claims == null)
                return;
            claimsIdentity = identity as System.Security.Claims.ClaimsIdentity;
            if (claimsIdentity != null)
            {
                foreach (var claim in claims)
                {
                    item = Convert(claim);
                    claimsIdentity.AddClaim(item);
                }
            }
            else
            {
                claimProvider = identity as IClaimProvider;
                if (claimProvider != null)
                    claimProvider.AddClaims(claims);
            }
        }

        #endregion
        #region ClearClaims

        public void ClearClaims(IIdentity identity)
        {
            System.Security.Claims.ClaimsIdentity claimsIdentity;
            IClaimProvider claimProvider;

            if (identity == null)
                return;
            claimsIdentity = identity as System.Security.Claims.ClaimsIdentity;
            if (claimsIdentity != null)
            {
                var items = claimsIdentity.Claims.ToList();
                foreach (var item in items)
                    claimsIdentity.TryRemoveClaim(item);
            }
            else
            {
                claimProvider = identity as IClaimProvider;
                if (claimProvider != null)
                    claimProvider.ClearClaims();
            }
        }

        #endregion
        #region FindClaim

        public Claim FindClaim(IIdentity identity, string claimType)
        {
            System.Security.Claims.ClaimsIdentity claimsIdentity;
            System.Security.Claims.Claim claim;
            IClaimProvider claimProvider;

            if (identity == null)
                return null;
            if (string.IsNullOrWhiteSpace(claimType))
                return null;
            claimsIdentity = identity as System.Security.Claims.ClaimsIdentity;
            if (claimsIdentity != null)
            {
                if (!string.IsNullOrWhiteSpace(claimType))
                    claim = claimsIdentity.FindFirst(claimType);
                else
                    claim = claimsIdentity.Claims.FirstOrDefault();
                if (claim == null)
                    return null;
                return Convert(claim);
            }
            else
            {
                claimProvider = identity as IClaimProvider;
                if (claimProvider != null)
                    return claimProvider.FindClaim(claimType);
            }
            return null;
        }

        #endregion
        #region FindClaims

        public ClaimCollection FindClaims(IIdentity identity, string claimType)
        {
            System.Security.Claims.ClaimsIdentity claimsIdentity;
            IEnumerable<System.Security.Claims.Claim> claims;
            ClaimCollection items;
            IClaimProvider claimProvider;

            if (identity == null)
                return null;
            items = new ClaimCollection();
            claimsIdentity = identity as System.Security.Claims.ClaimsIdentity;
            if (claimsIdentity != null)
            {
                if (!string.IsNullOrWhiteSpace(claimType))
                    claims = claimsIdentity.FindAll(claimType);
                else
                    claims = claimsIdentity.Claims;
                foreach (var claim in claims)
                    items.Add(claim.Type, claim.Value, claim.ValueType);
            }
            else
            {
                claimProvider = identity as IClaimProvider;
                if (claimProvider != null)
                    return claimProvider.FindClaims(claimType);
            }
            return items;
        }

        #endregion
        #region HasClaim

        public bool HasClaim(IIdentity identity, string claimType, string value)
        {
            System.Security.Claims.ClaimsIdentity claimsIdentity;
            IClaimProvider claimProvider;

            if (identity == null)
                return false;
            claimsIdentity = identity as System.Security.Claims.ClaimsIdentity;
            if (claimsIdentity != null)
            {
                return claimsIdentity.HasClaim(claimType, value);
            }
            else
            {
                claimProvider = identity as IClaimProvider;
                if (claimProvider != null)
                    return claimProvider.HasClaim(claimType, value);
            }
            return false;
        }

        #endregion
        #region RemoveClaim

        public bool RemoveClaim(IIdentity identity, Claim claim)
        {
            System.Security.Claims.ClaimsIdentity claimsIdentity;
            System.Security.Claims.Claim item;
            IClaimProvider claimProvider;

            if (identity == null)
                return false;
            if (claim == null)
                return false;
            if (string.IsNullOrWhiteSpace(claim.ClaimType))
                return false;
            claimsIdentity = identity as System.Security.Claims.ClaimsIdentity;
            if (claimsIdentity != null)
            {
                item = claimsIdentity.FindFirst(claim.ClaimType);
                if ((item != null) && (item.Value.Equals(claim.Value, true, System.StringComparison.OrdinalIgnoreCase)))
                    return claimsIdentity.TryRemoveClaim(item);
            }
            else
            {
                claimProvider = identity as IClaimProvider;
                if (claimProvider != null)
                    return claimProvider.RemoveClaim(claim);
            }
            return false;
        }

        #endregion
        #region RemoveClaims

        public void RemoveClaims(IIdentity identity, IEnumerable<Claim> claims)
        {
            System.Security.Claims.ClaimsIdentity claimsIdentity;
            System.Security.Claims.Claim item;
            IClaimProvider claimProvider;

            if (identity == null)
                return;
            if (claims == null)
                return;
            claimsIdentity = identity as System.Security.Claims.ClaimsIdentity;
            if (claimsIdentity != null)
            {
                foreach (var claim in claims)
                {
                    item = claimsIdentity.FindFirst(claim.ClaimType);
                    if ((item != null) && (item.Value.Equals(claim.Value, true, System.StringComparison.OrdinalIgnoreCase)))
                        claimsIdentity.TryRemoveClaim(item);
                }
            }
            else
            {
                claimProvider = identity as IClaimProvider;
                if (claimProvider != null)
                    claimProvider.RemoveClaims(claims);
            }
        }

        #endregion
        #region ToString

        public override string ToString()
        {
            return "ClaimManager - ClaimsIdentity and IClaimProvider";
        }

        #endregion

        #endregion
        #region Private Members

        #region Convert

        private static System.Security.Claims.Claim Convert(Claim item)
        {
            if (item == null)
                return null;
            return new System.Security.Claims.Claim(item.ClaimType, item.Value, item.ValueType);
        }
        private static Claim Convert(System.Security.Claims.Claim item)
        {
            if (item == null)
                return null;
            return new Claim()
            {
                ClaimType = item.Type,
                Value = item.Value,
                ValueType = item.ValueType,
            };
        }

        #endregion

        #endregion
    }
}
